<?php
/*
 * kernel/object.view.php 
 * 
 * templates engine
 * 
 * Copyright (C) 2010, Taras Kudla
 * 
 */
/*
 * Templater:  
 * { %if condition1 [=,not,eq,>,<,>=,<=] condition2} text {else} here {/if}
 * { %loop i }text here{/loop}
 * { %acl(1,2,3,4,5)} 1 - action, [2 - params, 3 - value, 4 - optional html 5 - runfile ]
 * { %action(1,2,3)} 1 - action, [2 - params, 3 - runfile]
 * { %lang keyname }
 * { %syslang keyname }
 * { #varname }
 * { %typeof #varname }
 * { %count #varname }
 * { %date([dateformat]}
 * { %callaction action }
 * { %sys kernel|version|language|debug|calltrace|encoding }
 */
class view extends kernel
{
    /*
     * NOTE: FILETYPE OF ALL TEMPALES SHOULD BE ".html"
     */
    private $url = null;
    private $CurrentTplMod = null;
    private $tempatesDirectory = null;
    private $templatesUrl      = null;
    private $modsurl		   = null;
    private $jscoreurl		   = null;
    private $tplCache = array();
    private $maxTplFileSize = 10485760; // in bytes, default = 10kb
    private $maxLoopIterations = 500;
    private $varNamePattern = "[^0-9]+|[A-z_]+[0-9]{1,3})\]";
    private $engine = null;
    private $defaultengine = "pcre";
	
    # kernel object initialization
    public function init (){
		$this->url  =$this->core->url();
		$this->templatesDirectory = $this->core->parseasdir($this->core->get("templatesdir"));
		$this->templatesUrl = $this->core->parseasurl($this->core->get("templatesurl"));
		$this->modsurl = $this->core->parseasurl($this->core->get("modsurl"));
		$this->jscoreurl = $this->core->parseasurl($this->core->get("jscoreurl"));
		# setting up templates engine
		$engine = $this->core->get("tplengine");
		if( $engine == null){
			$engine = $this->defaultengine;
		}
		# file
		$enginefile = $this->core->kernelpath()."tplengines/"."engine.".$engine.".php";
		if( !file_exists($enginefile)){
			$this->core->error("view","Cannot found system templates parsing engine");
			return false;
		}
		require_once($enginefile);
		$name = "engine_".$engine;
		$engine = new $name($this->core);
		//var_dump($engine);
		
		if( $engine instanceof tplengine){
			# linking object
			$this->engine = & $engine;
		} else {
			$this->core->error("view","Templates parsing engine '$name' shound be instance of tplengine");
			return false;
		}
		return true;
		
	}
	public function getmodsurl(){
		return $this->modsurl;
	}
	public function getjscoreurl(){
		return $this->jscoreurl;
	}
	public function gettemplatesdir(){
		return $this->templatesDirectory;
	}
	public function gettemplatesurl(){
		return $this->templatesUrl;
	}

	# alias to loadviewmodel
    public function flushmodel(){
    	return $this->LoadViewModel();
    }
	# main global template parser
	public function & loadviewmodel(){
		$startpoint = microtime(1);
		$modelname = $this->core->get("viewmodel");
		if ($this->core->get("runmode") == _CONSOLE_RUNMODE){
			print "ViewModels in console mode are disabled...\n";
			return null;
		}
		$link = $this->templatesUrl.$modelname."/";
		$tfile = $this->templatesDirectory.$modelname."/page.html";
		$templateData = $this->loadtemplatedata($tfile);
		$templateData = $this->engine->parser($templateData);
		# images, css, js files replacing
		$templateData = preg_replace("/<link([^>]+)href\s*=\s*(['\"])(?!http|https|\/|{sys url})([^\"']+)\\2([^>]*)>/is",
			"<link$1href=$2" . $link . "$3$2$4>", $templateData);
		$templateData = preg_replace("/<img([^>]+)src\s*=\s*(['\"])(?!http|https|{sys url}|\/)([^\"']+)\\2([^>]*)\>/isU",
			"<img$1src=$2" . $link . "$3$2$4>", $templateData);
		$templateData = preg_replace("/<script([^>]+)src\s*=\s*(['\"])(?!http|https|{sys url}|\/)([^\"']+)\\2([^>]*)\>/isU",
			"<script$1src=$2" . $link . "$3$2$4>", $templateData);
		# global output areas data inserting
		if( $this->core->isloaded("base") ){
			$outvalues=$this->core->base->getoutvalues();        
			$outdata  =$this->core->base->getoutdata();
			foreach ($outvalues as $key => &$data){
				asort($data,SORT_NUMERIC);
				$outputdata = null;
				foreach($data as $action=> &$value){
					$outputdata .= $outdata[$action]["data"];
				}
				$templateData = preg_replace("/\{\s*\%output\s+".$key."\s*\}/i",$outputdata,$templateData);
			}
		}
		/*
		 * parsing system title
		 */
		if( $this->core->base->htmltitle!=null){
			$templateData = preg_replace("/\<\s*title\s*\>(.+)\<\/\s*title\s*\>/isU","<title>".$this->core->base->htmltitle."</title>",$templateData);
		}
		$this->core->profiler("view","template '$modelname' loaded and data parsed",$startpoint);
		return $templateData;
	}


	
	/*
	 * 
	 */
	
	public function & parse( & $text,$data = null, $language = null ){
		if( is_object($this->engine)){
			$this->engine->parsetext($text,$data, $language);	
		}
		return $text;
	}


   	
	# template path and url detection
	public function detecttemplate($mod, $tpl){
		# checking if need system template
		if ($mod == "system"){
			$file = $this->core->path()."view/templates/".$this->core->get("viewmodel")."/_system_/" . $tpl;
			return file_exists($file) ? array($file,$this->url."view/templates/" .$this->core->get("viewmodel"). "/_system_/"):false;
		} else {
			$file = $this->templatesDirectory.$this->core->get("viewmodel"). "/_mod_/" . $mod . "/" . $tpl;
			$file2 = $this->core->parseasdir($this->core->get("modsdir")). $mod . "/tpl/" . $tpl;
		}
		if (file_exists($file)){
			return array($file,$this->url."view/templates/" .$this->core->get("viewmodel"). "/_mod_/" . $mod . "/");
		}
		if (file_exists($file2)){
			return array($file2,$this->modsurl. $mod . "/tpl/");
		}
		return false;
	}

	# alias for next method
    public function template($tpl, $vars = null,$mod=null,$parsephp=false){
    	return $this->GetTemplate($tpl, $vars ,$mod,$parsephp);
    }
    
	# parsing template 
	public function & GetTemplate($tpl, $vars = null,$mod=null,$parsephp=false){
		$startTime = microtime(1);
		$data = null;
		# checking if console
		if ($this->core->get("runmode") == _CONSOLE_RUNMODE){
			return null;
		}
		# checking if module name is not entered
		if( $mod == null && $this->core->Getenvlayer()==_ENV_MOD ){
			$env = $this->core->Getenvcaller();	
			$mod = $env["MOD"];
		}
		$this->CurrentTplMod = $mod;
		$this->engine->CurrentTplMod = $mod;
		if( preg_match("/\.php$/",$tpl)){
			$useasphp = true;
		} else {
			$tpl.=".html";
			$useasphp = false;
		}
		
		# parsing template file path and url
		list($file, $url) = $this->detecttemplate($mod, $tpl);
		if ($file == null || $url == null){
			$this->core->error("VIEW", "Cannot found template for '" . $mod . "' - '" . $tpl . "'");
			return false;
		}
		# checking if template is a php file
		# linking template vars data
		$this->engine->setvars($vars);
		if( !$useasphp ){
		# checking if template was previously loaded
		if (isset($this->tplCache[$file])){
			$data = $this->tplCache[$file];
		} else {
			# loading template data
			$data = $this->loadtemplatedata($file);
		}
		# Parsing all data 
		$data = $this->engine->parser($data);
		} else {
			ob_start();
			# preparing global environment
			$lang = $this->core->lang->getlangobj($this->core->getenvcaller("mod"));
			# trying to disable kernel environment
			$tmpcore = $this->core;
			$this->core=null;
			# preparing for variables
			extract($vars, EXTR_REFS, "tpl_");
			# 
			require_once($file);
			# redtoring kernel environment
			$this->core=$tmpcore;
			# unsetting variables
			unset($data);
			unset($lang);
			# output buffer data
			$data=ob_get_contents();
			ob_end_clean();
			# parsing data
			if($parsephp)
			$data = $this->engine->parser($data);
		}
		# checking if page title defined
		if( preg_match("/\<\s*title\s*\>(.+)\<\/\s*title\s*\>/isU",$data,$tmp)){
			$this->core->base->htmltitle = $tmp[1];
		}
		# Images sources replacement
		$data = preg_replace("/<img([^>]+)src\s*=\s*(['\"])(?!http|https|{sys way}|{ME}|\/)([^\"']+)\\2([^>]*)>/isU", "<img$1src=$2".$url."$3$2$4>", $data);
		# Css files replacement
		$data = preg_replace("/<link([^>]+)href\s*=\s*(['\"])(?!http|https|\/|{sys way}|\/)([^\"']+)\\2([^>]*)>/is", "<link$1href=$2".$url."$3$2$4>", $data);
		$data = preg_replace("/<script([^>]+)src\s*=\s*(['\"])(?!http|https|\/|{sys way}|\/)([^\"']+)\\2([^>]*)>/is", "<script$1src=$2".$url."$3$2$4>", $data);
		# Replacing document.cookie,window.cookie
		$data = preg_replace(array("/document\.cookie/i","/window\.cookie/i"), array("'document-cookie'","'window-cookie'"), $data);
		# Simple way replacement
		$data = preg_replace("/{ME}/Us", $url, $data);
		# NOTE: Forms actions will changed only if it's empty ( form is connected with current event).
		# If you want to connect your form with other events please use {ACTION} expression.
		if ($this->core->get("runmode") == _AJAX_RUNMODE){
			# Updating forms to general configuration
			# NOTE: Only if form action="" (empty)
			$data = preg_replace("/<form([^>]+)action\s*=\s*([\"']{2})([^>]*)>/is", "<form$1action=\"" . $this->core->getenvcaller("ID"). "\"$3>", $data);
			# Updating button for action
			$data = preg_replace("/<input([^>])type=([\"'])?(submit)\\2([^>]*)>/is", "<input$1type=$2Button$2 onClick=$2javascript:processForm(this.form);$2 $4>", $data);
		}
		# setting template data to null
		$this->GlobalData = null;
		$this->core->profiler("view","template '$tpl' parsed",$startTime);    
		return $data;
	}
	
	# system templates parsing
	public function systemplate($template,$var=null){
		if(!is_array($var))$var=array();
		$file = $this->templatesDirectory.$this->core->get("viewmodel")."/_system_/".$template.".html";
		if( file_exists($file)){
			$data = $this->loadtemplatedata($file);
			if( $this->core->isloaded("lang")){
				$lang = &$this->core->lang;
			} else $lang = null;
			$data = $this->parse($data,$var,$lang);
			$url  = $this->templatesUrl."".$this->core->get("viewmodel")."/_system_/";
			$data = preg_replace("/<img([^>]+)src\s*=\s*(['\"])(?!http|https|{sys way}|\/)([^\"']+)\\2([^>]*)>/isU", "<img$1src=$2" . $url . "$3$2$4>", $data);
			$data = preg_replace("/<link([^>]+)href\s*=\s*(['\"])(?!http|https|\/|{sys way}|\/)([^\"']+)\\2([^>]*)>/is", "<link$1href=$2" . $url . "$3$2$4>", $data);
			$data = preg_replace("/<script([^>]+)src\s*=\s*(['\"])(?!http|https|\/|{sys way}|\/)([^\"']+)\\2([^>]*)>/is", "<script$1src=$2" . $url . "$3$2$4>", $data);			
			return $data;
		} else { 
			$this->core->error("VIEW","System template '$template' no found");
			return false;
		}
		return true;
	}

	# this method was created for optimizing templates vs caching engine
	public function & loadtemplatedata($filename){
		# Checking for caching engine
		if( $this->core->get("usecache") &&  $this->core->isloaded("cache")){
			# Checking if template is in memory alreay
			$name = "gepard.view.".md5($filename);
			$datename = $name.".date";
			$ctime = $this->core->cache->get($datename);
			if( $ctime ){
				$mtime = filemtime($filename);
				if( $mtime > $ctime){
					#need to rebuild cache
					$filedata=file_get_contents($filename);
					$this->core->cache->set($datename,time());
					$this->core->cache->set($name,$filedata);
					$this->core->debug("view","rebuilding cache for template '' ");
				}else {
					#returning data from cache
					$filedata = $this->core->cache->get($name);
					$this->core->debug("view","getting template from cache");
				}
			} else {
				# need to build cache
				$filedata=file_get_contents($filename);
				$this->core->cache->set($datename,time());
				$this->core->cache->set($name,$filedata);
				$this->core->debug("view","putting template data into cache");			
			}			
		} else {
			# anyway, returning back a text data
			$filedata=file_get_contents($filename);	
		}
		return $filedata;
	}
  }
?>
